<?php defined('SYSPATH') OR die('No direct access allowed.');

class Lexico extends Core_Lexico {

	public function __construct($input){
		parent::__construct();
		$this->setInput($input);
	}
	
	/**
	 * Cria uma lista de Tokens com toda a string de entrada.
	 */
	public function listTokens(){
		$list = array();
		$tk = null;
		try{
			while ($this->hasInput()){
				$tk = $this->nextToken();
				$list[] = $tk; 
			}
		}catch(LexicalError $le){
			echo $le->getMessage();
		}
		return $list;
	}
	
	/**
	 * Retorna o proximo token
	 * @return Token
	 */
    public function nextToken(){
    	if ( ! $this->hasInput() )
            return null;
        //$c = $this->getChar();
        $c = $this->nextChar();
		//Verifica e pula todos os espa�os em branco
        while ($this->hasInput()){
			if($this->isEB($c)){
				$c = $this->nextChar();
			}else if($this->isNL($c)){
				$this->col = -1;
				$this->row++;
				$c = $this->nextChar();
			}else{
				break;
			}
        }
        if($this->reconheceTokenSimples($c)){
        	$token = new Token($this->col, $this->row);
        	$token->setId($c);
			$token->setLexeme($c);
			$token->setPosition($this->position-1);
        	//$this->nextChar();
        }elseif($this->isL($c)){
        	/**
        	 * Esse caractere � letra, ent�o entra na fun��o e volta uma posicao
        	 * para percorrer toda a palavra
        	 */        	
        	$token = $this->reconheceIdentificador($this->position-1);
        }elseif($this->isASS($c)||$this->isASD($c)){
        	/**
        	 * Esse caractere � uma aspa, ent�o entra na fun��o e volta uma posicao
        	 * para percorrer toda a string
        	 */
        	$token = $this->reconheceString($this->position-1);
        }elseif($this->isC($c)){
        	/**
        	 * Esse caractere � uma caractere de compara��o ! = < >, ent�o entra na 
        	 * fun��o e volta uma posi��o para procurar por uma continua��o != <= >=
        	 */
        	$token = $this->reconheceComparacao($this->position-1);
        }elseif($this->isOP($c)){
        	/**
        	 * Esse caractere � uma caractere de opera��o + - * / , ent�o entra na 
        	 * fun��o e volta uma posi��o
        	 */
        	$token = new Token($this->col, $this->row);
        	$token->setId(self::t_OPERACAO);
			$token->setLexeme($c);
			$token->setPosition($this->position-1);
        }elseif($this->isD($c)){
        	/**
        	 * Esse caractere � um numero, ent�o entra na 
        	 * fun��o para percorrer todos os outros numeros
        	 */
        	$token = $this->reconheceNumero($this->position-1);
        }else{
        	//throw new LexicalError('Caractere Invalido' , $this->position);
        	$token = new Token($this->col, $this->row);
        	$token->setId(self::ERRORLEX);
        	$token->setLexeme("Caractere Invalido(".$c.")");
        	$token->setPosition($this->position-1);
        }
        return $token;
    }
	
    /**
     * Reconhece um identificador 
     * Faz o reconhecimento apartir do 2caractere
     * @param $start
     * @return Token
     */
	public function reconheceIdentificador($start){
		$token = new Token($this->col, $this->row);
		$c = $this->nextChar();
		while ($c!='-1'){
			if(($this->isA($c))||($c=='_')){ // se for alpha numerico
				$c = $this->nextChar();
			}elseif($this->isEB($c)){// se for espa�o em branco, quebra de linha ou tab
				break;
			}else{ //final da entrada
				//throw new LexicalError('Identificador Invalido.', $start);
				$this->position--;
				break;
			}
		}
		$lexema = substr($this->input, $start, $this->position-$start);
		$lexema = trim($lexema); //retira espa�os em branco antes e depois da string
		if(strtoupper($lexema)==self::t_SELECAO){
			$token->setId(self::t_SELECAO);
		}elseif(strtoupper($lexema)==self::t_PROJECAO){
			$token->setId(self::t_PROJECAO);
		}elseif(strtoupper($lexema)==self::t_CARTESIANO){
			$token->setId(self::t_CARTESIANO);
		}elseif(strtoupper($lexema)==self::t_JUNCAO){
			$token->setId(self::t_JUNCAO);
		}elseif(strtoupper($lexema)==self::t_UNIAO){
			$token->setId(self::t_UNIAO);
		}elseif(strtoupper($lexema)==self::t_AND){
			$token->setId(self::t_AND);
		}elseif(strtoupper($lexema)==self::t_OR){
			$token->setId(self::t_OR);
		}elseif(strtoupper($lexema)==self::t_NOT){
			$token->setId(self::t_NOT);
		}else{
			$token->setId(self::t_IDENTIFICADOR);
		}
		$token->setLexeme($lexema);
		$token->setPosition($start);
		return $token;
	}
    
    /**
     * Reconhece uma string 
     * Faz o reconhecimento apartir do 2caractere
     * @param $start
     * @return Token
     */
	public function reconheceString($start){
		$token = new Token($this->col, $this->row);
		$c = $this->nextChar();
		while ($c!='-1'){
			if($this->isASS($c)||$this->isASD($c)){ // se for aspas
				break;
			}else{ //qualquer outra coisa
				$c = $this->nextChar();
			}
		}
		$lexema = substr($this->input, $start, $this->position-$start);
		$token->setId(self::t_STRING);
		$token->setLexeme($lexema);
		$token->setPosition($start);
		return $token;
	}
	
    /**
     * Reconhece um numero
     * Faz o reconhecimento apartir do 2caractere
     * @param $start
     * @return Token
     */
	public function reconheceNumero($start){
		$token = new Token($this->col, $this->row);
		$c = $this->nextChar();
		$real = false;
		while ($c!='-1'){
			if($this->isD($c)){ // se for numerico
				$c = $this->nextChar();
			}else if($c=='.'){
				$real = true;
				$c = $this->nextChar();
			}else{ //final da entrada
				$this->position--;
				break;
			}
		}
		$lexema = substr($this->input, $start, $this->position-$start);
		$lexema = trim($lexema); //retira espa�os em branco antes e depois da string
		
		//$token->setId(self::t_NUMERO);
		if($real==true){
			$token->setId(self::t_REAL);
		}else{
			$token->setId(self::t_INTEIRO);
		}
		$token->setLexeme($lexema);
		$token->setPosition($start);
		return $token;
	}
	
   /**
     * Reconhece uma compara��o 
     * Faz o reconhecimento apartir do 2caractere
     * @param $start
     * @return Token
     */
	public function reconheceComparacao($start){
		$token = new Token($this->col, $this->row);
		$ca = $this->getPrevChar(); 
		if($ca==">"||$ca=="<"||$ca=="!"){ //se o caractere anterior for um dos operadores compostos
			$c = $this->getChar();
			if($c=="="){ //se o caractere atual for igual ent�o >= <= !=
				$this->nextChar();
			}
		}else{
			//n�o pegue o proximo caractere. operador simples
		}
		$lexema = substr($this->input, $start, $this->position-$start);
		$token->setId(self::t_COMPARACAO);
		$token->setLexeme($lexema);
		$token->setPosition($start);
		return $token;
	}
	
    /**
     * Reconhece um token fixo simples, como ',', '.', '(' ou ')' 
     * @param $c char a ser analizado
     * @return Boolean
     */
	public function reconheceTokenSimples($c){
		if($c==self::t_PONTO||
			$c==self::t_VIRGULA||
			$c==self::t_ABREPAR||
			$c==self::t_FECHAPAR){
			return true;
		}else{
			return false;
		}
	}
    
} // End Token